1   /*
2    * Copyright 2002-2012 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.beans.factory.config;
18  
19  import java.io.Serializable;
20  
21  import org.springframework.beans.BeansException;
22  import org.springframework.beans.factory.BeanFactory;
23  import org.springframework.beans.factory.ObjectFactory;
24  import org.springframework.util.Assert;
25  
26  /**
27   * A {@link org.springframework.beans.factory.FactoryBean} implementation that
28   * returns a value which is an {@link org.springframework.beans.factory.ObjectFactory}
29   * that in turn returns a bean sourced from a {@link org.springframework.beans.factory.BeanFactory}.
30   *
31   * <p>As such, this may be used to avoid having a client object directly calling
32   * {@link org.springframework.beans.factory.BeanFactory#getBean(String)} to get
33   * a (typically prototype) bean from a
34   * {@link org.springframework.beans.factory.BeanFactory}, which would be a
35   * violation of the inversion of control principle. Instead, with the use
36   * of this class, the client object can be fed an
37   * {@link org.springframework.beans.factory.ObjectFactory} instance as a
38   * property which directly returns only the one target bean (again, which is
39   * typically a prototype bean).
40   *
41   * <p>A sample config in an XML-based
42   * {@link org.springframework.beans.factory.BeanFactory} might look as follows:
43   *
44   * <pre class="code">&lt;beans&gt;
45   *
46   *   &lt;!-- Prototype bean since we have state --&gt;
47   *   &lt;bean id="myService" class="a.b.c.MyService" scope="prototype"/&gt;
48   *
49   *   &lt;bean id="myServiceFactory"
50   *       class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean"&gt;
51   *     &lt;property name="targetBeanName"&gt;&lt;idref local="myService"/&gt;&lt;/property&gt;
52   *   &lt;/bean&gt;
53   *
54   *   &lt;bean id="clientBean" class="a.b.c.MyClientBean"&gt;
55   *     &lt;property name="myServiceFactory" ref="myServiceFactory"/&gt;
56   *   &lt;/bean&gt;
57   *
58   *&lt;/beans&gt;</pre>
59   *
60   * <p>The attendant {@code MyClientBean} class implementation might look
61   * something like this:
62   *
63   * <pre class="code">package a.b.c;
64   *
65   * import org.springframework.beans.factory.ObjectFactory;
66   *
67   * public class MyClientBean {
68   *
69   *   private ObjectFactory&lt;MyService&gt; myServiceFactory;
70   *
71   *   public void setMyServiceFactory(ObjectFactory&lt;MyService&gt; myServiceFactory) {
72   *     this.myServiceFactory = myServiceFactory;
73   *   }
74   *
75   *   public void someBusinessMethod() {
76   *     // get a 'fresh', brand new MyService instance
77   *     MyService service = this.myServiceFactory.getObject();
78   *     // use the service object to effect the business logic...
79   *   }
80   * }</pre>
81   *
82   * <p>An alternate approach to this application of an object creational pattern
83   * would be to use the {@link ServiceLocatorFactoryBean}
84   * to source (prototype) beans. The {@link ServiceLocatorFactoryBean} approach
85   * has the advantage of the fact that one doesn't have to depend on any
86   * Spring-specific interface such as {@link org.springframework.beans.factory.ObjectFactory},
87   * but has the disadvantage of requiring runtime class generation. Please do
88   * consult the {@link ServiceLocatorFactoryBean ServiceLocatorFactoryBean JavaDoc}
89   * for a fuller discussion of this issue.
90   *
91   * @author Colin Sampaleanu
92   * @author Juergen Hoeller
93   * @since 1.0.2
94   * @see org.springframework.beans.factory.ObjectFactory
95   * @see ServiceLocatorFactoryBean
96   */
97  public class ObjectFactoryCreatingFactoryBean extends AbstractFactoryBean<ObjectFactory<Object>> {
98  
99  	private String targetBeanName;
100 
101 
102 	/**
103 	 * Set the name of the target bean.
104 	 * <p>The target does not <i>have</i> to be a non-singleton bean, but realistically
105 	 * always will be (because if the target bean were a singleton, then said singleton
106 	 * bean could simply be injected straight into the dependent object, thus obviating
107 	 * the need for the extra level of indirection afforded by this factory approach).
108 	 */
109 	public void setTargetBeanName(String targetBeanName) {
110 		this.targetBeanName = targetBeanName;
111 	}
112 
113 	@Override
114 	public void afterPropertiesSet() throws Exception {
115 		Assert.hasText(this.targetBeanName, "Property 'targetBeanName' is required");
116 		super.afterPropertiesSet();
117 	}
118 
119 
120 	@Override
121 	public Class<?> getObjectType() {
122 		return ObjectFactory.class;
123 	}
124 
125 	@Override
126 	protected ObjectFactory<Object> createInstance() {
127 		return new TargetBeanObjectFactory(getBeanFactory(), this.targetBeanName);
128 	}
129 
130 
131 	/**
132 	 * Independent inner class - for serialization purposes.
133 	 */
134 	@SuppressWarnings("serial")
135 	private static class TargetBeanObjectFactory implements ObjectFactory<Object>, Serializable {
136 
137 		private final BeanFactory beanFactory;
138 
139 		private final String targetBeanName;
140 
141 		public TargetBeanObjectFactory(BeanFactory beanFactory, String targetBeanName) {
142 			this.beanFactory = beanFactory;
143 			this.targetBeanName = targetBeanName;
144 		}
145 
146 		@Override
147 		public Object getObject() throws BeansException {
148 			return this.beanFactory.getBean(this.targetBeanName);
149 		}
150 	}
151 
152 }